#include <iostream>
// #include <string>
#include <memory>
#include <poll.h>

#include "Socket.hpp"

using namespace SockModule;
using namespace LogModule;

#define MAX 1024

const int default_fd = -1;

class PollSvr
{
    
    void Test(){
        for(int i = 0; i < MAX; ++i){
            if(_fds[i].fd == default_fd){
                continue;
            }
            std::cout << "fd:" << _fds[i].fd << '[' << Event2Str(_fds[i].events) << "]    ";
        }
        std::cout << std::endl;
    }
    std::string Event2Str(short event){
        std::string str = (event & POLLIN) ? "POLLIN" : "";
        str += ((event&POLLOUT)? "POLLOUT" : "");
        return str; 
    }
public:
    PollSvr(uint16_t port)
        : _port(port), _listen_sock(std::make_unique<TcpSocket>())
    {
    }
    ~PollSvr() {}

    void Init()
    {
        _listen_sock->BuildTcpSocket(_port);
        for (int i = 1; i < MAX; i++)
        {
            _fds[i].fd = default_fd;
            _fds[i].events = _fds[i].revents = 0;
        }
        _fds[0].fd = _listen_sock->Fd();
        // _fds[0].events |= POLLIN;
        _fds[0].events |= POLLIN;
    }
    void Loop()
    {
        _isrunning = true;

        while (_isrunning)
        {
            int milliSec = 1000; // 一秒内阻塞 超过一秒非阻塞
            // int milliSec = 0; // 非阻塞
            // int milliSec = -1; // 一直阻塞

            int n = poll(_fds, MAX, milliSec);
            switch (n)
            {
            case 0:
                std::cout << "timeout ..." << std::endl;
                break;
            case -1:
                perror("poll: ");
                break;
            default:
                std::cout << "IO affair ready." << std::endl;
                Dispatcher();
                Test();
                break;
            }
        }

        _isrunning = false;
    }
    void Accepter()
    {
        InetAddr client;
        int n = _listen_sock->Accepter(&client);
        if(n < 0)
            return;

        std::cout << "获得了一个新的链接: " << n << " client info: " << client.Addr() << std::endl;
        int pos = -1;
        for(int i = 0; i < MAX; ++i){
            if(_fds[i].fd == default_fd){
                pos = i;
                break;
            }
        }
        if(pos == default_fd){
            //可以扩容了,目前不考虑.
            LOG(LogLevel::ERROR) << "服务器繁忙";
            close(n);
        }
        // 空位找到
        else{
            _fds[pos].fd = n;
            _fds[pos].events = POLLIN;
        }
    }
    void Recever(int index)
    {
        char buffer[1024];
        ssize_t n = recv(_fds[index].fd, buffer, sizeof(buffer) - 1, 0);
        if(n > 0){
            buffer[n] = 0;
            std::cout << "client# " << buffer << std::endl;
            // 回显
            std::string msg = "echo# ";
            msg += buffer;
            send(_fds[index].fd, msg.c_str(), msg.size(), 0); // bug
        }
        else if(n == 0){
            // 远端关闭
            LOG(LogLevel::DEBUG) << "客户端退出, sockfd: " << _fds[index].fd;
            close(_fds[index].fd);
            // 复原
            _fds[index].fd = default_fd;
            _fds[index].events = _fds[index].revents = 0;
        }
        else{
            LOG(LogLevel::DEBUG) << "客户端读取出错, sockfd: " << _fds[index].fd;
            close(_fds[index].fd);
            _fds[index].fd = default_fd;
        }
    }
    void Dispatcher()
    {
        for(int i = 0; i < MAX; ++i){
            if(_fds[i].fd == default_fd){
                continue;
            }
            // 合法的fd
            if(_fds[i].fd == _listen_sock->Fd()){
                // listen_sockfd
                if(_fds[i].revents & POLLIN){
                    Accepter();
                }
            }
            else {
                if(_fds[i].revents & POLLIN){
                    Recever(i);
                }
                // else if(_fds[i]->revents & POLLOUT){
                //     //write
                // }
            }

        }
    }


private:
    uint16_t _port;
    std::unique_ptr<Socket> _listen_sock;
    bool _isrunning;
    struct pollfd _fds[MAX];
    // struct pollfd *_fds;
};
